package com.banciyuan.bcywebview.utils.file;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.os.Build;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Created by hfxt2008 on 14-7-30.
 * 这个图片存储工具类，现在只有选图片存储的时候才会用到（改头像，发多图）
 * 主要定义了两个默认存储路径 IMAGE_FILE_URI 和 IMAGE_FILE_URI
 */
public class ImageManager {

    public final static String TEMP_NAME = "bcy_temp";
    public final static String FILE_SUCCESS = "file_success";
    public final static String FILE_ERROR = "file_error";
    public final static int BLUR_RADIUS = 4;

    public static String getImageFile(Context mContext) {
        File file = mContext.getExternalFilesDir(null);
        if (file != null) {
            return file.getAbsolutePath() + "/.bcy_cache/";
        } else {
            return mContext.getFilesDir() + "/.bcy_cache/";
        }
    }

    public static String getVideoFile(Context mContext) {
        File file = mContext.getExternalFilesDir(null);
        if (file != null) {
            return file.getAbsolutePath() + "/.bcy_cache/.bcy_video/";
        } else {
            return mContext.getFilesDir() + "/.bcy_cache/.bcy_video/";
        }
    }

    public static String getBigTempFile(Context mContext) {
        File file = mContext.getExternalFilesDir(null);
        if (file != null) {
            return file.getAbsolutePath() + "/.bcy_cache/tmp/";
        } else {
            return mContext.getFilesDir() + "/.bcy_cache/tmp/";
        }
    }

    public static String getTemp(Context mContext) {
        File file = mContext.getExternalFilesDir(null);
        if (file != null) {
            String dicPath = file.getAbsolutePath() + "/.bcy_cache/.bcy_temp/";
            File dic = new File(dicPath);
            if (!dic.exists()) {
                dic.mkdirs();
            }
            return dicPath;
        } else {
            String dicPath = mContext.getFilesDir() + "/.bcy_cache/.bcy_temp/";
            File dic = new File(dicPath);
            if (!dic.exists()) {
                dic.mkdirs();
            }
            return dicPath;
        }
    }

    public static String saveTempImage(Context mContext, Bitmap bm, String name, Boolean ifResize, float size, int reformSize) {
        return saveTempImage(mContext, bm, name, ifResize, size, reformSize, 0);
    }

    public static String saveTempImageifBig(Context mContext, Bitmap bm, String name, Boolean ifResize, float size, int reformSize, int degree) {
        try {
            Bitmap bitmap = null;
            if (bm != null) {
                if (ifResize) {
                    bitmap = imageTranslateScaleIfBig(bm, size, degree);
                } else {
                    bitmap = bm;
                }
            } else {
                return FILE_ERROR;
            }
            saveFile(mContext, bitmap, name, reformSize);
            return FILE_SUCCESS;
        } catch (Exception e) {
            return FILE_ERROR;
        }
    }

    public static String saveTempImage(Context mContext, Bitmap bm, String name, Boolean ifResize, float size, int reformSize, int degree) {
        try {
            Bitmap bitmap = null;
            if (bm != null) {
                if (ifResize) {
                    bitmap = imageTranslateScale(bm, size, degree);
                } else {
                    bitmap = bm;
                }
            } else {
                return FILE_ERROR;
            }
            saveFile(mContext, bitmap, name, reformSize);
            return FILE_SUCCESS;
        } catch (Exception e) {
            return FILE_ERROR;
        }
    }

    private static Bitmap imageTranslateScale(Bitmap bm, float size, int degree) {
        Matrix matrix = new Matrix();
        int width = bm.getWidth();
        int height = bm.getHeight();
        float w = size / (float) bm.getWidth();
        matrix.postScale(w, w);
        matrix.postRotate(degree);
        Bitmap bitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
        return bitmap;
    }

    private static Bitmap imageTranslateScaleIfBig(Bitmap bm, float size, int degree) {
        Matrix matrix = new Matrix();
        int width = bm.getWidth();
        int height = bm.getHeight();
        float w = size / (float) bm.getWidth();
        if (w < 1) {
            matrix.postScale(w, w);
        }
        matrix.postRotate(degree);
        Bitmap bitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
        return bitmap;
    }

    private static void saveFile(Context mContext, Bitmap bitmap, String name, int reformSize) throws Exception {
        File tempFile = new File(getTemp(mContext));
        if (!tempFile.exists()) {
            tempFile.mkdirs();
        }
        FileOutputStream fOutSrc = null;
        fOutSrc = new FileOutputStream(tempFile.getPath() + "/" + name);
        if (bitmap != null) {
            bitmap.compress(Bitmap.CompressFormat.JPEG, reformSize, fOutSrc);
        } else {
            fOutSrc.flush();
            fOutSrc.close();
        }
        fOutSrc.flush();
        fOutSrc.close();
    }

    public static void clearTemp(Context mContext) {
        File tempfile = new File(getTemp(mContext) + ImageManager.TEMP_NAME);
        if (new File(getTemp(mContext)).exists()) tempfile.delete();
    }

    public static Bitmap getTempImage(int size, String path) {
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        newOpts.inSampleSize = size;// 设置缩放比例
        return BitmapFactory.decodeFile(path, newOpts);
    }

    //用来得到图片的exif中旋转角度的信息
    public static int readPictureDegree(String path) {
        int degree = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    public static Bitmap fastblur(Bitmap sentBitmap) {
        return fastblur(sentBitmap, BLUR_RADIUS);
    }

    //快速高斯模糊函数，谨慎调用
    public static Bitmap fastblur(Bitmap sentBitmap, int radius) {

        if (sentBitmap == null || sentBitmap.isRecycled()) return null;

        Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);

        int w = bitmap.getWidth();
        int h = bitmap.getHeight();

        int[] pix = new int[w * h];
        bitmap.getPixels(pix, 0, w, 0, 0, w, h);

        int wm = w - 1;
        int hm = h - 1;
        int wh = w * h;
        int div = radius + radius + 1;

        int r[] = new int[wh];
        int g[] = new int[wh];
        int b[] = new int[wh];
        int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
        int vmin[] = new int[Math.max(w, h)];

        int divsum = (div + 1) >> 1;
        divsum *= divsum;
        int dv[] = new int[256 * divsum];
        for (i = 0; i < 256 * divsum; i++) {
            dv[i] = (i / divsum);
        }

        yw = yi = 0;

        int[][] stack = new int[div][3];
        int stackpointer;
        int stackstart;
        int[] sir;
        int rbs;
        int r1 = radius + 1;
        int routsum, goutsum, boutsum;
        int rinsum, ginsum, binsum;

        for (y = 0; y < h; y++) {
            rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
            for (i = -radius; i <= radius; i++) {
                p = pix[yi + Math.min(wm, Math.max(i, 0))];
                sir = stack[i + radius];
                sir[0] = (p & 0xff0000) >> 16;
                sir[1] = (p & 0x00ff00) >> 8;
                sir[2] = (p & 0x0000ff);
                rbs = r1 - Math.abs(i);
                rsum += sir[0] * rbs;
                gsum += sir[1] * rbs;
                bsum += sir[2] * rbs;
                if (i > 0) {
                    rinsum += sir[0];
                    ginsum += sir[1];
                    binsum += sir[2];
                } else {
                    routsum += sir[0];
                    goutsum += sir[1];
                    boutsum += sir[2];
                }
            }
            stackpointer = radius;

            for (x = 0; x < w; x++) {

                r[yi] = dv[rsum];
                g[yi] = dv[gsum];
                b[yi] = dv[bsum];

                rsum -= routsum;
                gsum -= goutsum;
                bsum -= boutsum;

                stackstart = stackpointer - radius + div;
                sir = stack[stackstart % div];

                routsum -= sir[0];
                goutsum -= sir[1];
                boutsum -= sir[2];

                if (y == 0) {
                    vmin[x] = Math.min(x + radius + 1, wm);
                }
                p = pix[yw + vmin[x]];

                sir[0] = (p & 0xff0000) >> 16;
                sir[1] = (p & 0x00ff00) >> 8;
                sir[2] = (p & 0x0000ff);

                rinsum += sir[0];
                ginsum += sir[1];
                binsum += sir[2];

                rsum += rinsum;
                gsum += ginsum;
                bsum += binsum;

                stackpointer = (stackpointer + 1) % div;
                sir = stack[(stackpointer) % div];

                routsum += sir[0];
                goutsum += sir[1];
                boutsum += sir[2];

                rinsum -= sir[0];
                ginsum -= sir[1];
                binsum -= sir[2];

                yi++;
            }
            yw += w;
        }
        for (x = 0; x < w; x++) {
            rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
            yp = -radius * w;
            for (i = -radius; i <= radius; i++) {
                yi = Math.max(0, yp) + x;
                sir = stack[i + radius];

                sir[0] = r[yi];
                sir[1] = g[yi];
                sir[2] = b[yi];

                rbs = r1 - Math.abs(i);

                rsum += r[yi] * rbs;
                gsum += g[yi] * rbs;
                bsum += b[yi] * rbs;

                if (i > 0) {
                    rinsum += sir[0];
                    ginsum += sir[1];
                    binsum += sir[2];
                } else {
                    routsum += sir[0];
                    goutsum += sir[1];
                    boutsum += sir[2];
                }

                if (i < hm) {
                    yp += w;
                }
            }
            yi = x;
            stackpointer = radius;
            for (y = 0; y < h; y++) {
                // Preserve alpha channel: ( 0xff000000 & pix[yi] )
                pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];

                rsum -= routsum;
                gsum -= goutsum;
                bsum -= boutsum;

                stackstart = stackpointer - radius + div;
                sir = stack[stackstart % div];

                routsum -= sir[0];
                goutsum -= sir[1];
                boutsum -= sir[2];

                if (x == 0) {
                    vmin[y] = Math.min(y + r1, hm) * w;
                }
                p = x + vmin[y];

                sir[0] = r[p];
                sir[1] = g[p];
                sir[2] = b[p];

                rinsum += sir[0];
                ginsum += sir[1];
                binsum += sir[2];

                rsum += rinsum;
                gsum += ginsum;
                bsum += binsum;

                stackpointer = (stackpointer + 1) % div;
                sir = stack[stackpointer];

                routsum += sir[0];
                goutsum += sir[1];
                boutsum += sir[2];

                rinsum -= sir[0];
                ginsum -= sir[1];
                binsum -= sir[2];

                yi += w;
            }
        }
        bitmap.setPixels(pix, 0, w, 0, 0, w, h);
        return (bitmap);
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
    private static Bitmap rsBlur(Context context, Bitmap sentBitmap) throws Exception {
        if (sentBitmap == null || sentBitmap.isRecycled()) return null;
        Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
        RenderScript rs = null;
        try {
            rs = RenderScript.create(context);
            rs.setMessageHandler(new RenderScript.RSMessageHandler());
            Allocation input =
                    Allocation.createFromBitmap(rs, sentBitmap, Allocation.MipmapControl.MIPMAP_NONE,
                            Allocation.USAGE_SCRIPT);
            Allocation output = Allocation.createTyped(rs, input.getType());
            ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));

            blur.setInput(input);
            blur.setRadius(BLUR_RADIUS);
            blur.forEach(output);
            output.copyTo(bitmap);
        } finally {
            if (rs != null) {
                rs.destroy();
            }
        }

        return bitmap;
    }

    public static Bitmap blur(Context context, Bitmap sentBitmap) {
        return fastblur(sentBitmap);
    }
}